#include "stdafx.h"
#include "Adapter.h"
#include <sstream>
#include "Adapters.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

namespace serika
{
	namespace db
	{
		Adapter::Adapter()
		{
		}
	
		Adapter::~Adapter()
		{
		}
	
		Adapter* Adapter::Create(const std::string& adapterName, const Any& initInfo)
		{
			Adapter* adapter = 0;
			if (adapterName == "mysql")
			{
				//adapter = MysqlAdapter::NewAdapter(initInfo);
			}
			else if (adapterName == "sqlite")
			{
				adapter = new SqliteAdapter();
			}

			if (!adapter->Create(initInfo))
			{
				delete adapter;
				adapter = 0;
			}
			return adapter;
		}
	
		std::string Adapter::ConstructConditions(const std::string &column, const db::Any &value)
		{
			std::stringstream ss;
			if (value.type() == typeid(std::string))
			{
				ss << "(`" << column << "`='" << this->EscapeString(value.Get<std::string>()) << "')";
			}
			else
			{
				ss << "(`" << column << "`='" << value << "')";
			}
			return ss.str();
		}
	
		std::string Adapter::ConstructConditions(const std::string& column, const std::vector<Any>& values)
		{
			std::stringstream ss;
			ss << "(`" << column << "` IN (";
			for (std::vector<Any>::const_iterator itr = values.begin(); itr != values.end(); ++itr)
			{
				if (itr != values.begin())
				{
					ss << ",";
				}
				if (itr->type() == typeid(std::string))
				{
					ss << "'" << this->EscapeString(itr->Get<std::string>()) << "'";
				}
				else
				{
					ss << "'" << (*itr) << "'";
				}
			}
			ss << "))";
			return ss.str();
		}
	
		std::string Adapter::ConstructIdConditions(int id)
		{
			std::stringstream ss;
			ss << "(`id`='" << id << "')";
			return ss.str();
		}
	
		std::string Adapter::ConstructIdConditions(const std::vector<int>& ids)
		{
			std::stringstream ss;
			ss << "(`id` IN (";
			for (std::vector<int>::const_iterator itr = ids.begin(); itr != ids.end(); ++itr)
			{
				if (itr != ids.begin())
				{
					ss << ",";
				}
				ss << "'" << (*itr) << "'";
			}
			ss << "))";
			return ss.str();
		}

		std::string Adapter::ConstructSelect(const std::string& tableName, 
			const std::string& conditions, 
			int offset,
			int limit,
			const std::string& select, 
			const std::string& joins, 
			const std::string& order, 
			const std::string& group,
			const std::string& having)
		{
			std::stringstream sql;
			sql << "SELECT " << select << " FROM `" << tableName << "`";
			if (!joins.empty())
			{
				sql << " " << joins;
			}
			if (!conditions.empty())
			{
				sql << " WHERE " << conditions;
			}
			if (!order.empty())
			{
				sql << " ORDER BY " << order;
			}
			if (!group.empty())
			{
				sql << " GROUP BY " << group;
				if (!having.empty())
				{
					sql << " HAVING " << having;
				}
			}
			if (offset > 0 || limit > 0)
			{
				sql << " LIMIT " << offset << "," << limit;
			}
			return sql.str();
		}

		std::string Adapter::ConstructInsert(const FieldMap* fields, const std::string& tableName)
		{
			std::stringstream ss, f, v;
			f << "(";
			v << "(";
			for (FieldMap::const_iterator itr = fields->begin(); itr != fields->end(); ++itr)
			{
				if (itr != fields->begin())
				{
					f << ",";
					v << ",";
				}
				f << "`" << itr->first << "`";
				if (itr->second.type() == typeid(std::string))
				{
					v << "'" << this->EscapeString(itr->second.Get<std::string>()) << "'";
				}
				else
				{
					v << "'" << itr->second << "'";
				}
			}
			f << ")";
			v << ")";
			ss << "INSERT INTO `" << tableName << "` " << f.str() << " VALUES" << v.str();
			return ss.str();
		}

		std::string Adapter::ConstructMultipleInsert(const std::vector<FieldMap*>& fieldMaps, const std::string& tableName)
		{
			std::stringstream ss, f, v;
			ss << "INSERT INTO `" << tableName << "` ";

			const FieldMap* fields = fieldMaps.back();
			f << "(";
			for (FieldMap::const_iterator itr = fields->begin(); itr != fields->end(); ++itr)
			{
				if (itr != fields->begin())
				{
					f << ",";
				}
				f << "`" << itr->first << "`";
			}
			f << ")";
			ss << f.str() << " VALUES";

			for (std::vector<FieldMap*>::const_iterator itr = fieldMaps.begin(); itr != fieldMaps.end(); ++itr)
			{
				if (itr != fieldMaps.begin())
				{
					v << ",";
				}
				v << "(";
				fields = *itr;
				for (FieldMap::const_iterator itr2 = fields->begin(); itr2 != fields->end(); ++itr2)
				{
					if (itr2 != fields->begin())
					{
						v << ",";
					}
					if (itr2->second.type() == typeid(std::string))
					{
						v << "'" << this->EscapeString(itr2->second.Get<std::string>()) << "'";
					}
					else 
					{
						v << "'" << itr2->second << "'";
					}
				}
				v << ")";
			}
			ss << v.str();

			return ss.str();
		}

		bool Adapter::UpdateRecord(const db::FieldMap *fields, const std::string &tableName, 
			const std::string &column, const Any& value)
		{
			std::string settings, conditions;
			this->PrepareUpdateSql(settings, conditions, fields, tableName, column, value);
			return this->UpdateAllRecords(settings, conditions, tableName) == 1;
		}

		std::string Adapter::ConstructUpdate(const std::string &tableName, const std::string &settings, const std::string &conditions)
		{
			std::stringstream ss;
			ss << "UPDATE `" << tableName << "` SET " << settings;
			if (!conditions.empty())
			{
				ss << " WHERE " << conditions;
			}
			return ss.str();
		}

		std::string Adapter::ConstructDelete(const std::string& tableName, const std::string& conditions)
		{
			std::stringstream ss;
			ss << "DELETE FROM `" << tableName << "`";
			if (!conditions.empty())
			{
				ss << " WHERE " << conditions;
			}
			return ss.str();
		}

		inline void Adapter::PrepareUpdateSql(std::string& settings, 
			std::string& conditions, 
			const FieldMap* fields, 
			const std::string& /*tableName*/, 
			const std::string& column,
			const Any& value)
		{
			std::stringstream ss;
			ss << "`" << column << "`='" << ((value.type() == typeid(std::string)) ? this->EscapeString(value.Get<std::string>()) : value) << "'";
			conditions = ss.str();
			ss.str("");

			for (FieldMap::const_iterator itr = fields->begin(); itr != fields->end(); ++itr)
			{
				if (itr != fields->begin())
				{
					ss << ",";
				}
				if (itr->second.type() == typeid(std::string))
				{
					ss << "`" << itr->first << "`='"  << this->EscapeString(itr->second.Get<std::string>()) << "'";
				}
				else
				{
					ss << "`" << itr->first << "`='"  << itr->second << "'";
				}
			}
			settings = ss.str();
		}
	}
}
